package com.alogic.xscript.plugins;

import com.alogic.xscript.AbstractLogiclet;
import com.alogic.xscript.ExecuteWatcher;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.doc.XsObject;
import com.anysoft.formula.*;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import org.apache.commons.lang3.StringUtils;

import java.util.regex.Pattern;

/**
 * 增强Formula
 *
 * @version 1.6.13.23 [20201030 duanyy] <br>
 * - 优化xscript的日志机制  <br>
 */
public class FormulaExt extends AbstractLogiclet {
    protected String id;
    protected String $expr = "";
    protected String $dft = "";

    public FormulaExt(String tag, Logiclet p) {
        super(tag, p);
    }

    public void configure(Properties p){
        super.configure(p);
        id = PropertiesConstants.getString(p,"id","$" + this.getXmlTag(),true);
        $expr = PropertiesConstants.getRaw(p,"expr",$expr);
        $dft = PropertiesConstants.getRaw(p,"dft",$dft);
    }

    @Override
    protected void onExecute(XsObject root, XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
        String formula = PropertiesConstants.transform(ctx,$expr,"");
        try {
            if (StringUtils.isNotEmpty(formula)) {
                Parser parser = new MyParser();
                Expression expr = parser.parse(formula);
                String value = expr.getValue(ctx).toString();
                ctx.SetValue(id, value);
            }else{
                ctx.SetValue(id,PropertiesConstants.transform(ctx,$dft,""));
            }
        }catch (Exception ex){
            log("Failed to execute fomula:" + formula,LOG_ERROR,ctx);
            ctx.SetValue(id,PropertiesConstants.transform(ctx,$dft,""));
        }
    }

    public static class MyParser extends Parser{
        protected Expression variant(String id) {
            return new MyVariant(id);
        }
    }

    public static class MyVariant extends Expression.Variant{
        public static final Pattern lType = Pattern.compile("^[\\+\\-]?[0-9]*$");
        public static final Pattern dType = Pattern.compile("^[\\+\\-]?[0-9]*\\.?[0-9]*$");
        public static final Pattern eType = Pattern.compile("^[\\+\\-]?[0-9]+[\\.][0-9]*?[Ee][+-]?[0-9]+?$");
        public MyVariant(String name) {
            super(name);
        }

        public ExprValue getValue(DataProvider provider) {
            if (provider == null) {
                throw new FormulaException("Data provider is null,can not get value of " + this.varName);
            } else {
                if (this.varContext == null) {
                    this.varContext = provider.getContext(this.varName);
                }

                String value = provider.getValue(this.varName, this.varContext, (String)null);
                if (StringUtils.isEmpty(value)){
                    return new ExprValue(0);
                }
                if (isLong(value)){
                    return new ExprValue(getLong(value,0));
                }

                if (isDouble(value)){
                    return new ExprValue(getDouble(value,0.0));
                }
                return value != null ? new ExprValue(value) : null;
            }
        }

        public static boolean isLong(String v){
            return lType.matcher(v).find();
        }

        public static long getLong(String v,long dft){
            try{
                return Long.parseLong(v);
            }catch (NumberFormatException ex){
                return dft;
            }
        }

        public static boolean isDouble(String v){
            return dType.matcher(v).find() || eType.matcher(v).find();
        }

        public static double getDouble(String v,double dft){
            try{
                return Double.parseDouble(v);
            }catch (NumberFormatException ex){
                return dft;
            }
        }
    }
}